package com.sayyi.validate.valid;

import com.sayyi.validate.constraints.custom.UniqueValidator;

import javax.validation.Validation;
import javax.validation.Validator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 验证工具构造工厂
 * @author xuchuang
 * date 2021/12/7 3:16 PM
 */
public final class ValidateUtilFactory {

    private ValidateUtilFactory() throws IllegalAccessException {
        throw new IllegalAccessException();
    }

    private static final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();

    public static <T> ValidateUtilBuilder<T> builder(List<T> datas) {
        Objects.requireNonNull(datas, "校验数据集合不能为空");
        return new ValidateUtilBuilder<>(datas, validator);
    }

    public static class ValidateUtilBuilder<T> {
        private ValidateUtilBuilder(List<T> datas, Validator validator) {
            Objects.requireNonNull(datas);
            this.datas = datas;
            this.validator = validator;
        }
        /** 验证组件 */
        private final Validator validator;
        /** 待验证数据 */
        private final List<T> datas;
        /** 验证数据缓存 */
        private Map<String, Map<Object, Object>> mapMap;

        /**
         * 内部数据重复校验
         * @param key
         * @return
         */
        public ValidateUtilBuilder<T> dataRepeatCheck(String key) {
            return dataRepeatCheck(key, 1);
        }

        /**
         * 内部数据重复校验
         * @param key
         * @param offset 重复校验时，需要展示重复数据所在行。这个参数会影响输出的行信息。行=offset+index
         * @return
         */
        public ValidateUtilBuilder<T> dataRepeatCheck(String key, int offset) {
            // 记录元素出现位置
            putMap(key, new HashMap<T, Integer>());
            // 记录整体的下标
            Map<String, Integer> indexMap = new HashMap<>();
            indexMap.put(UniqueValidator.UNIQUE_INDEX_MAP_KEY, offset);
            putMap(key + UniqueValidator.UNIQUE_INDEX_KEY_SUFFIX, indexMap);
            return this;
        }

        @SuppressWarnings("unchecked")
        public ValidateUtilBuilder<T> putMap(String key, Map value) {
            if (mapMap == null) {
                mapMap = new HashMap<>(8);
            }
            if (mapMap.containsKey(key)) {
                throw new IllegalArgumentException("已经绑定了相同名称[" + key + "]的数据");
            }
            mapMap.put(key, value);
            return this;
        }

        /**
         * 构造验证器，并验证数据。因此验证器是一次性的（为了释放缓存），所以采用这种方式来处理。
         * @return
         */
        public List<ValidateResult<T>> buildAndValid(Class<?>... groups) {
            if (datas == null || datas.isEmpty()) {
                throw new NullPointerException("未设置验证数据");
            }
            return new ValidateUtil<T>(datas, mapMap, validator).valid(groups);
        }
    }
}
